home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / OutOfPhase1.01Source / OutOfPhase Folder / Level 0 Macintosh 07Aug94 / Screen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-01  |  47.5 KB  |  1,574 lines  |  [TEXT/KAHL]

  1. /* Screen.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    System Dependency Library for Building Portable Software               */
  5. /*    Macintosh Version                                                      */
  6. /*    Written by Thomas R. Lawrence, 1993 - 1994.                            */
  7. /*                                                                           */
  8. /*    This file is Public Domain; it may be used for any purpose whatsoever  */
  9. /*    without restriction.                                                   */
  10. /*                                                                           */
  11. /*    This package is distributed in the hope that it will be useful,        */
  12. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  13. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                   */
  14. /*                                                                           */
  15. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  16. /*                                                                           */
  17. /*****************************************************************************/
  18.  
  19. #include "MiscInfo.h"
  20. #include "Debug.h"
  21. #include "Audit.h"
  22. #include "Definitions.h"
  23.  
  24. #pragma options(pack_enums)
  25. #include <Quickdraw.h>
  26. #include <Windows.h>
  27. #include <Menus.h>
  28. #include <Fonts.h>
  29. #include <TextEdit.h>
  30. #include <Dialogs.h>
  31. #include <Script.h>
  32. #include <GestaltEqu.h>
  33. #pragma options(!pack_enums)
  34.  
  35. #include "Screen.h"
  36. #include "Menus.h"
  37. #include "Memory.h"
  38. #include "EventLoop.h"
  39. #include "Scrap.h"
  40. #include "Array.h"
  41. #include "Files.h"
  42.  
  43.  
  44. /* maximum string length that can be sized in a single call to TextWidth or DrawText */
  45. /* (such a big number doesn't actually make much sense since 65535 is the number of */
  46. /* pixels, so if there are 32767 chars, we are way over the QuickDraw limit.) */
  47. #define MAXTEXTSIZING (32767)
  48.  
  49.  
  50. /* this structure contains everything about a window */
  51. struct WinType
  52.     {
  53.         /* document window or dialog box */
  54.         WinForm                                WhatKindOfWindow;
  55.         /* callback routine for redrawing it */
  56.         void                                    (*UpdateRoutine)(void* Refcon);
  57.         /* reference value for callback */
  58.         void*                                    Refcon;
  59.         /* current clip rect (for AddClipRect) */
  60.         Rect                                    CurrentClipRect;
  61.         /* actual window record */
  62.         WindowRecord                    ActualWindow;
  63.     };
  64.  
  65.  
  66. /* structure for bitmap */
  67. struct Bitmap
  68.     {
  69.         /* bytes per row for larger than image or partial bitmaps */
  70.         short                                    BytesPerRow; /* 2 bytes */
  71.         /* dimensions of bitmap */
  72.         OrdType                                Width; /* 2 bytes */
  73.         OrdType                                Height; /* 2 bytes */
  74.         /* the bitmap that the system uses */
  75.         BitMap                                SystemBitmap; /* 14 bytes */
  76.         /* data array here (block will actually be as large as necessary) */
  77.         char                                    Data[1]; /* long word aligned (20th offset) */
  78.     };
  79.  
  80.  
  81. /* list of windows */
  82. static ArrayRec*                    OurWindowList;
  83.  
  84. /* list of windows that need to be updated */
  85. static ArrayRec*                    PendingDeferredUpdates;
  86.  
  87. /* debugging flag */
  88. EXECUTE(static MyBoolean    Initialized = False;)
  89.  
  90. /* pattern bitmap definitions.  patterns are 8x8 pixel blocks */
  91. static unsigned char            PatternMapping[5][8] =
  92.     {
  93.         {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, /* White */
  94.         {0x88,0x22,0x88,0x22,0x88,0x22,0x88,0x22}, /* Light Grey */
  95.         {0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55}, /* Medium Grey */
  96.         {0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD}, /* Dark Grey */
  97.         {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF} /* Black */
  98.     };
  99.  
  100. /* since I don't know how to get a list of fonts, I make this menu */
  101. /* which contains all of the fonts and then I extract the names from it */
  102. static MenuHandle                    FunnyFontMenu;
  103.  
  104. /* this array contains all of the modal dialog boxes.  the most recent one is */
  105. /* at the end of the array */
  106. static ArrayRec*                    DialogBoxList; /* of WinType's */
  107.  
  108.  
  109. /* Initialize the screen management subsystem.  This routine must be called before */
  110. /* any graphics routines are called.  this routine initializes the entire Level 0 */
  111. /* module set except for some optional modules (like Network).  if it returns  */
  112. /* False then initialization failed and the program must terminate immediately. */
  113. MyBoolean                        InitializeScreen(void)
  114.     {
  115.         ERROR(Initialized,PRERR(ForceAbort,"InitializeScreen called more than once"));
  116.         /* initialize operating system managers */
  117.         InitGraf(&qd.thePort);
  118.         InitFonts();
  119.         InitWindows();
  120.         TEInit();
  121.         InitDialogs(NIL);
  122.         InitCursor();
  123.         InitMenus();
  124. #ifdef THINK_C
  125.     #if /*__option(mc68020) ||*/ __option(mc68881)
  126.         {
  127.             long                Result;
  128.  
  129.             if (noErr != Gestalt(gestaltFPUType,&Result))
  130.                 {
  131.                     return False;
  132.                 }
  133.             if (Result == gestaltNoFPU)
  134.                 {
  135.                     PRERR(ForceAbort,"This program requires a floating point coprocessor.");
  136.                     return False;
  137.                 }
  138.         }
  139.     #endif
  140.     #if __option(profile)
  141.         {
  142.             void                InitializeProfile(void);
  143.  
  144.             InitializeProfile();
  145.         }
  146.     #endif
  147. #endif
  148.         /* initialize our local memory manager */
  149.         if (!Eep_InitMemory())
  150.             {
  151.              FailurePoint1:
  152.                 return False;
  153.             }
  154.         /* initialize error handling.  no return code from this */
  155.         Eep_InitPRERR();
  156.         /* initialize our window array */
  157.         OurWindowList = NewArray();
  158.         if (OurWindowList == NIL)
  159.             {
  160.              FailurePoint2:
  161.                 Eep_FlushMemory();
  162.                 goto FailurePoint1;
  163.             }
  164.         /* initialize our deferred update list */
  165.         PendingDeferredUpdates = NewArray();
  166.         if (PendingDeferredUpdates == NIL)
  167.             {
  168.              FailurePoint3:
  169.                 DisposeArray(OurWindowList);
  170.                 goto FailurePoint2;
  171.             }
  172.         /* create dialog box array here */
  173.         DialogBoxList = NewArray();
  174.         if (DialogBoxList == NIL)
  175.             {
  176.              FailurePoint4:
  177.                 DisposeArray(PendingDeferredUpdates);
  178.                 goto FailurePoint3;
  179.             }
  180.         /* initialize cut and paste */
  181.         if (!Eep_InitializeScrapHandler())
  182.             {
  183.              FailurePoint5:
  184.                 DisposeArray(DialogBoxList);
  185.                 goto FailurePoint4;
  186.             }
  187.         /* initialize event loop */
  188.         if (!Eep_InitEventLoop())
  189.             {
  190.              FailurePoint6:
  191.                 Eep_ShutdownScrapHandler();
  192.                 goto FailurePoint5;
  193.             }
  194.         /* initialize menu subsystem */
  195.         if (!Eep_InitializeMenus())
  196.             {
  197.              FailurePoint7:
  198.                 Eep_ShutdownEventLoop();
  199.                 goto FailurePoint6;
  200.             }
  201.         /* initialize file system */
  202.         if (!Eep_InitializeFiles())
  203.             {
  204.              FailurePoint8:
  205.                 Eep_ShutdownMenus();
  206.                 goto FailurePoint7;
  207.             }
  208.         /* create the font menu for obtaining names of fonts */
  209.         /* menu manager uses menu IDs 256 and up, so we'll grab ID 1 */
  210.         FunnyFontMenu = NewMenu(1,"\pSilly Stupid Little Font Menu");
  211.         if (FunnyFontMenu == NIL)
  212.             {
  213.              FailurePoint9:
  214.                 Eep_ShutdownFiles();
  215.                 goto FailurePoint8;
  216.             }
  217.         AddResMenu(FunnyFontMenu,'FONT');
  218.         /* initialization done */
  219.         EXECUTE(Initialized = True;)
  220.         return True;
  221.     }
  222.  
  223.  
  224. /* close all open windows and perform any cleanup or server disconnection before */
  225. /* the program terminates */
  226. void                                ShutdownScreen(void)
  227.     {
  228.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  229.         /* shutdown subsystems in reverse order */
  230.         DisposeMenu(FunnyFontMenu); /* get rid of the funny font menu */
  231.         Eep_ShutdownFiles();
  232.         Eep_ShutdownMenus();
  233.         Eep_ShutdownEventLoop();
  234.         Eep_ShutdownScrapHandler();
  235.         /* clean up our own data structures */
  236.         ERROR(ArrayGetLength(OurWindowList) != 0,PRERR(AllowResume,
  237.             "ShutdownScreen:  there are still some windows open"));
  238.         DisposeArray(OurWindowList);
  239.         DisposeArray(PendingDeferredUpdates);
  240.         DisposeArray(DialogBoxList);
  241.         /* dump memory subsystem */
  242.         Eep_FlushMemory();
  243.         Eep_ShutdownPRERR();
  244.         EXECUTE(Initialized = False;)
  245. #ifdef THINK_C
  246.     #if __option(profile)
  247.         {
  248.             void                DumpProfile(void);
  249.             void                ProfileKillElement(unsigned char* FunctionName);
  250.  
  251.             ProfileKillElement("\pGetAnEvent");
  252.             ProfileKillElement("\pRelinquishCPUCheckCancel");
  253.             ProfileKillElement("\pPutFile");
  254.             ProfileKillElement("\pGetFileStandard");
  255.             ProfileKillElement("\pGetFileAny");
  256.             DumpProfile();
  257.         }
  258.     #endif
  259. #endif
  260.     }
  261.  
  262.  
  263. /* get size of screen.  If there are multiple screens, the result is implementation */
  264. /* defined, but should not be counted on.  On the Macintosh, this returns only the */
  265. /* size of the main screen.  Caveats aside, you are guarranteed that there is at */
  266. /* least this much screen space in the form of a complete rectangle. */
  267. OrdType                            GetScreenHeight(void)
  268.     {
  269.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  270.         return qd.screenBits.bounds.bottom - qd.screenBits.bounds.top - GetMBarHeight();
  271.     }
  272.  
  273.  
  274. /* get size of screen.  If there are multiple screens, the result is implementation */
  275. /* defined, but should not be counted on.  On the Macintosh, this returns only the */
  276. /* size of the main screen.  Caveats aside, you are guarranteed that there is at */
  277. /* least this much screen space in the form of a complete rectangle. */
  278. OrdType                            GetScreenWidth(void)
  279.     {
  280.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  281.         return qd.screenBits.bounds.right - qd.screenBits.bounds.left;
  282.     }
  283.  
  284.  
  285. /* how big is a window's title bar */
  286. OrdType                            WindowTitleBarHeight(WinForm WindowKind)
  287.     {
  288.         switch (WindowKind)
  289.             {
  290.                 case eDocumentWindow:
  291.                     return 19;
  292.                 case eDialogWindow:
  293.                 case eModelessDialogWindow:
  294.                     return 6;
  295.                 default:
  296.                     EXECUTE(PRERR(AllowResume,"WindowTitleBarHeight:  Unknown window type"));
  297.             }
  298.     }
  299.  
  300.  
  301. /* how big are the other edges of a window */
  302. OrdType                            WindowOtherEdgeWidths(WinForm WindowKind)
  303.     {
  304.         switch (WindowKind)
  305.             {
  306.                 case eDocumentWindow:
  307.                     return 2;
  308.                 case eDialogWindow:
  309.                 case eModelessDialogWindow:
  310.                     return 6;
  311.                 default:
  312.                     EXECUTE(PRERR(AllowResume,"WindowTitleBarHeight:  Unknown window type"));
  313.             }
  314.     }
  315.  
  316.  
  317. /* create a new window.  if WindowKind = eDocumentWindow, then the window is a */
  318. /* standard window with a name (image is implementation defined).  In this case */
  319. /* Zoomable determines whether there will be a "Maximize" button, and Closable */
  320. /* determines whether there will be a "Close" button. */
  321. /* The window returned will be considered in the "disabled" state and any */
  322. /* objects installed in it should be disabled.  Eventually GetAnEvent will return */
  323. /* an active window change event disabling the window previously on top and */
  324. /* enabling this window.  if there are dialog boxes, then the window will be */
  325. /* created under the lowest dialog box */
  326. WinType*                        MakeNewWindow(WinForm WindowKind, WinCloseType Closable,
  327.                                             WinZoomType Zoomable, WinSizingType Resizing, OrdType Left,
  328.                                             OrdType Top, OrdType Width, OrdType Height,
  329.                                             void (*UpdateRoutine)(void* Refcon), void* Refcon)
  330.     {
  331.         WinType*                    Window;
  332.         Rect                            Where;
  333.         short                            WDef;
  334.  
  335.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  336.         ERROR(UpdateRoutine == NIL,PRERR(ForceAbort,
  337.             "MakeNewWindow:  can't have NIL update routine"));
  338.         /* allocate the window record */
  339.         Window = (WinType*)AllocPtrCanFail(sizeof(WinType),"WindowRecord");
  340.         if (Window == NIL)
  341.             {
  342.              FailurePoint1:
  343.                 return NIL;
  344.             }
  345.         /* add window to window list */
  346.         if (!ArrayAppendElement(OurWindowList,Window))
  347.             {
  348.              FailurePoint2:
  349.                 ReleasePtr((char*)Window);
  350.                 goto FailurePoint1;
  351.             }
  352.         /* create the actual window */
  353.         Where.left = Left;
  354.         Where.top = Top + GetMBarHeight();
  355.         Where.right = Left + Width;
  356.         Where.bottom = Top + Height + GetMBarHeight();
  357.         switch (WindowKind)
  358.             {
  359.                 case eDocumentWindow:
  360.                     if (Zoomable == eWindowZoomable)
  361.                         {
  362.                             WDef = zoomNoGrow;
  363.                         }
  364.                      else
  365.                         {
  366.                             WDef = noGrowDocProc;
  367.                         }
  368.                     break;
  369.                 case eDialogWindow:
  370.                     WDef = dBoxProc;
  371.                     break;
  372.                 case eModelessDialogWindow:
  373.                     WDef = movableDBoxProc;
  374.                     break;
  375.                 default:
  376.                     EXECUTE(PRERR(ForceAbort,"MakeNewWindow:  unknown WindowKind"));
  377.                     break;
  378.             }
  379.         if (NIL == NewWindow(&(Window->ActualWindow),&Where,"\p"/*notitle*/,
  380.             True/*visible*/,WDef,
  381.             (
  382.                 /* is the window a document window when there are dialog windows? */
  383.                 ((ArrayGetLength(DialogBoxList) != 0)
  384.                 && (WindowKind != eDialogWindow)
  385.                 && (WindowKind != eModelessDialogWindow))
  386.             ?
  387.                 /* yes -- create under lowest dialog */
  388.                 (GrafPort*)&(((WinType*)ArrayGetElement(DialogBoxList,0))->ActualWindow)
  389.             :
  390.                 /* no -- create on top */
  391.                 (GrafPort*)-1L/*windowinfront*/
  392.             ),(Closable == eWindowClosable),(long)Window/*refcon is window's base pointer*/))
  393.             {
  394.              FailurePoint3:
  395.                 ArrayDeleteElement(OurWindowList,ArrayFindElement(OurWindowList,Window));
  396.                 goto FailurePoint2;
  397.             }
  398.         /* initialize static fields */
  399.         Window->CurrentClipRect.left = 0;
  400.         Window->CurrentClipRect.top = 0;
  401.         Window->CurrentClipRect.right = Width;
  402.         Window->CurrentClipRect.bottom = Height;
  403.         Window->UpdateRoutine = UpdateRoutine;
  404.         Window->Refcon = Refcon;
  405.         Window->WhatKindOfWindow = WindowKind;
  406.         /* if it's a dialog box, then add it to the list */
  407.         if ((WindowKind == eDialogWindow) || (WindowKind == eModelessDialogWindow))
  408.             {
  409.                 if (!ArrayAppendElement(DialogBoxList,Window))
  410.                     {
  411.                         DisposeWindow((WindowPtr)&(Window->ActualWindow));
  412.                         goto FailurePoint3;
  413.                     }
  414.             }
  415.         return Window;
  416.     }
  417.  
  418.  
  419. /* change the size of the window.  The window will be guarranteed to be the specified */
  420. /* size, but significant portions may not be on screen, so be careful */
  421. void                                ResizeWindow(WinType* Window, OrdType Width, OrdType Height)
  422.     {
  423.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  424.         CheckPtrExistence(Window);
  425.         /* change window size */
  426.         SizeWindow((WindowPtr)&(Window->ActualWindow),Width,Height,False);
  427.         /* invalidate the window so it gets updated */
  428.         SetPort((WindowPtr)&(Window->ActualWindow));
  429.         InvalRect(&(Window->ActualWindow.port.portRect));
  430.     }
  431.  
  432.  
  433. /* close a window and release all associated space.  The window refnum may be reused */
  434. /* An active window change event will be issued activating the window that is */
  435. /* next in the stack.  If there are dialog boxes open, then the most recently */
  436. /* created one must be disposed or it is an error. */
  437. void                                KillWindow(WinType* Window)
  438.     {
  439.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  440.         CheckPtrExistence(Window);
  441.         ERROR((ArrayGetLength(DialogBoxList) != 0) && (ArrayFindElement(DialogBoxList,
  442.             Window) != ArrayGetLength(DialogBoxList) - 1),PRERR(ForceAbort,
  443.             "KillWindow:  dialog boxes exist and window isn't the topmost dialog box."));
  444.         Eep_WindowDying(Window);
  445.         ArrayDeleteElement(OurWindowList,ArrayFindElement(OurWindowList,Window));
  446.         if (ArrayGetLength(DialogBoxList) != 0)
  447.             {
  448.                 ERROR(ArrayFindElement(DialogBoxList,Window) == -1,PRERR(ForceAbort,
  449.                     "KillWindow:  couldn't find dialog box in the list"));
  450.                 ArrayDeleteElement(DialogBoxList,ArrayFindElement(DialogBoxList,Window));
  451.             }
  452.         /* remove it from the pending updates list if it's still there */
  453.         if (ArrayFindElement(PendingDeferredUpdates,Window) >= 0)
  454.             {
  455.                 ArrayDeleteElement(PendingDeferredUpdates,
  456.                     ArrayFindElement(PendingDeferredUpdates,Window));
  457.             }
  458.         /* dispose the OS window */
  459.         DisposeWindow((WindowPtr)&(Window->ActualWindow));
  460.         /* dispose the window object */
  461.         ReleasePtr((char*)Window);
  462.     }
  463.  
  464.  
  465. /* get the size of the usable portion of the window */
  466. OrdType                            GetWindowHeight(WinType* Window)
  467.     {
  468.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  469.         CheckPtrExistence(Window);
  470.         return Window->ActualWindow.port.portRect.bottom
  471.             - Window->ActualWindow.port.portRect.top;
  472.     }
  473.  
  474.  
  475. /* get the size of the usable portion of the window */
  476. OrdType                            GetWindowWidth(WinType* Window)
  477.     {
  478.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  479.         CheckPtrExistence(Window);
  480.         return Window->ActualWindow.port.portRect.right
  481.             - Window->ActualWindow.port.portRect.left;
  482.     }
  483.  
  484.  
  485. /* Get the global coordinate location of the window */
  486. OrdType                            GetWindowXStart(WinType* Window)
  487.     {
  488.         Point                            Delta = {0,0};
  489.  
  490.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  491.         CheckPtrExistence(Window);
  492.         /* this is really goofy, but I can't think of any other way of doing it. */
  493.         SetPort((WindowPtr)&(Window->ActualWindow));
  494.         LocalToGlobal(&Delta); /* find top-left with respect to screen */
  495.         return Delta.h;
  496.     }
  497.  
  498.  
  499. /* Get the global coordinate location of the window */
  500. OrdType                            GetWindowYStart(WinType* Window)
  501.     {
  502.         Point            Delta = {0,0};
  503.  
  504.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  505.         CheckPtrExistence(Window);
  506.         SetPort((WindowPtr)&(Window->ActualWindow));
  507.         LocalToGlobal(&Delta); /* find top-left with respect to screen */
  508.         return Delta.v - GetMBarHeight();
  509.     }
  510.  
  511.  
  512. /* Adjust the global position of the window. */
  513. void                                SetWindowPosition(WinType* Window, OrdType NewXLocation,
  514.                                             OrdType NewYLocation)
  515.     {
  516.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  517.         CheckPtrExistence(Window);
  518.         MoveWindow((WindowPtr)&(Window->ActualWindow),NewXLocation,
  519.             NewYLocation + GetMBarHeight(),False);
  520.     }
  521.  
  522.  
  523. /* Get what type of window it is */
  524. WinForm                            GetWindowKind(WinType* Window)
  525.     {
  526.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  527.         CheckPtrExistence(Window);
  528.         return Window->WhatKindOfWindow;
  529.     }
  530.  
  531.  
  532. /* allow system to resize window after user clicked in some area */
  533. void                                UserGrowWindow(WinType* Window, OrdType X, OrdType Y)
  534.     {
  535.         Rect                            Limits = {64,64,32767,32767};
  536.         Point                            Where;
  537.         unsigned long            NewSize;
  538.  
  539.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  540.         CheckPtrExistence(Window);
  541.         SetPort((WindowPtr)&(Window->ActualWindow));
  542.         Where.h = X;
  543.         Where.v = Y;
  544.         LocalToGlobal(&Where);
  545.         NewSize = GrowWindow((WindowPtr)&(Window->ActualWindow),Where,&Limits);
  546.         SizeWindow((WindowPtr)&(Window->ActualWindow),
  547.             NewSize & 0xffff,(NewSize >> 16) & 0xffff,False);
  548.         Limits.left = 0;
  549.         Limits.top = 0;
  550.         Limits.right = GetWindowWidth(Window);
  551.         Limits.bottom = GetWindowHeight(Window);
  552.         /* invalidate window so it gets redrawn */
  553.         EraseRect(&Limits);
  554.         InvalRect(&Limits);
  555.     }
  556.  
  557.  
  558. /* bring window to the top of the window stack.  this will be silently ignored */
  559. /* if there are dialog boxes open. */
  560. void                                ActivateThisWindow(WinType* Window)
  561.     {
  562.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  563.         CheckPtrExistence(Window);
  564.         if (ArrayGetLength(DialogBoxList) == 0)
  565.             {
  566.                 /* only do it if there aren't any dialog boxes */
  567.                 SelectWindow((WindowPtr)&(Window->ActualWindow));
  568.             }
  569.     }
  570.  
  571.  
  572. /* this function is used by MakeWindowFitOnScreen */
  573. static MyBoolean        SeeIfWindowFitsOnScreen(OrdType X, OrdType Y,
  574.                                             OrdType Width, OrdType Height)
  575.     {
  576.         RgnHandle                    OurRegion;
  577.         RgnHandle                    Intersection;
  578.         MyBoolean                    Result;
  579.  
  580.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  581.  
  582.         /* default value:  in case we run out of memory, don't do anything */
  583.         Result = True;
  584.         /* we add some constants in here to account for window title bar */
  585.         Y = Y + GetMBarHeight() - 19;
  586.         Height = Height + 19;
  587.  
  588.         /* create a region for the window the user wants to create */
  589.         OurRegion = NewRgn();
  590.         if (OurRegion != NIL)
  591.             {
  592.                 SetRectRgn(OurRegion,X,Y,X + Width,Y + Height);
  593.  
  594.                 /* create a region to get the intersection of the window & the screen */
  595.                 Intersection = NewRgn();
  596.                 if (Intersection != NIL)
  597.                     {
  598.                         /* find the intersection of the regions */
  599.                         SectRgn(GetGrayRgn(),OurRegion,Intersection);
  600.  
  601.                         /* if the window region and the intersection are equal, then the window */
  602.                         /* fits on the screen */
  603.                         Result = EqualRgn(Intersection,OurRegion);
  604.  
  605.                         DisposeRgn(Intersection);
  606.                     }
  607.  
  608.                 DisposeRgn(OurRegion);
  609.             }
  610.  
  611.         return Result;
  612.     }
  613.  
  614.  
  615. /* this routine helps make sure the rectangle fits on the screen.  If the rectangle */
  616. /* already fits on the screen, X and Y will not be adjusted, but if it doesn't, some */
  617. /* undefined adjustment will be made to ensure that the rectangle fits on the screen. */
  618. /* If the rectangle is so large that it can't be made to fit on the screen, then */
  619. /* the size of the window is reduced so that the window will fit on screen. */
  620. void                                MakeWindowFitOnScreen(OrdType* X, OrdType* Y,
  621.                                             OrdType* Width, OrdType* Height)
  622.     {
  623.         RgnHandle                    OurRegion;
  624.         RgnHandle                    Intersection;
  625.  
  626.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  627.         ERROR((X == NIL) || (Y == NIL) || (Width == NIL) || (Height == NIL),PRERR(ForceAbort,
  628.             "MakeWindowFitOnScreen:  an output parameter is NIL"));
  629.         if (!SeeIfWindowFitsOnScreen(*X,*Y,*Width,*Height))
  630.             {
  631.                 *X = 3;
  632.                 *Y = 23;
  633.                 if (!SeeIfWindowFitsOnScreen(*X,*Y,*Width,*Height))
  634.                     {
  635.                         if (*Width > GetScreenWidth() - *X - 2 - 1)
  636.                             {
  637.                                 *Width = GetScreenWidth() - *X - 2 - 1;
  638.                             }
  639.                         if (*Height > GetScreenHeight() - *Y - 2 - 1)
  640.                             {
  641.                                 *Height = GetScreenHeight() - *Y - 2 - 1;
  642.                             }
  643.                     }
  644.             }
  645.     }
  646.  
  647.  
  648. /* obtain the edge of a window, conforming to the user interface */
  649. /* guidelines of the implementation's platform */
  650. OrdType                            AlertLeftEdge(OrdType AlertWidth)
  651.     {
  652.         short                            Temp;
  653.  
  654.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  655.         Temp = (GetScreenWidth() - AlertWidth) / 2;
  656.         if (Temp < 4)
  657.             {
  658.                 Temp = 4;
  659.             }
  660.         return Temp;
  661.     }
  662.  
  663.  
  664. /* obtain the edge of a window, conforming to the user interface */
  665. /* guidelines of the implementation's platform */
  666. OrdType                            AlertTopEdge(OrdType AlertHeight)
  667.     {
  668.         short                            Temp;
  669.  
  670.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  671.         Temp = (GetScreenHeight() / 3) - AlertHeight;
  672.         if (Temp < 4 + 20 + GetMBarHeight())
  673.             {
  674.                 Temp = 4 + 20 + GetMBarHeight();
  675.             }
  676.         return Temp;
  677.     }
  678.  
  679.  
  680. /* obtain the edge of a window, conforming to the user interface */
  681. /* guidelines of the implementation's platform */
  682. OrdType                            DialogLeftEdge(OrdType DialogWidth)
  683.     {
  684.         short                            Temp;
  685.  
  686.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  687.         Temp = (GetScreenWidth() - DialogWidth) / 2;
  688.         if (Temp < 4)
  689.             {
  690.                 Temp = 4;
  691.             }
  692.         return Temp;
  693.     }
  694.  
  695.  
  696. /* obtain the edge of a window, conforming to the user interface */
  697. /* guidelines of the implementation's platform */
  698. OrdType                            DialogTopEdge(OrdType DialogHeight)
  699.     {
  700.         short                Temp;
  701.  
  702.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  703.         Temp = (GetScreenHeight() - DialogHeight) / 3;
  704.         if (Temp < 4 + 20 + GetMBarHeight())
  705.             {
  706.                 Temp = 4 + 20 + GetMBarHeight();
  707.             }
  708.         return Temp;
  709.     }
  710.  
  711.  
  712. /* change window's name.  name should be a null-terminated string.  the only windows */
  713. /* guarranteed to have a title bar are eDocumentWindow's. */
  714. void                                SetWindowName(WinType* Window, char* Name)
  715.     {
  716.         unsigned char            NameTemp[256];
  717.         long                            Scan;
  718.  
  719.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  720.         CheckPtrExistence(Window);
  721.         ERROR(Name == NIL,PRERR(ForceAbort,"SetWindowName:  name is NIL"));
  722.         Scan = 0;
  723.         while ((Scan < 255) && (Name[Scan] != 0))
  724.             {
  725.                 NameTemp[Scan + 1] = Name[Scan];
  726.                 Scan += 1;
  727.             }
  728.         NameTemp[0] = Scan;
  729.         SetWTitle((WindowPtr)&(Window->ActualWindow),NameTemp);
  730.     }
  731.  
  732.  
  733. /* invoke a window's update routine */
  734. void                                CallWindowUpdate(WinType* Window)
  735.     {
  736.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  737.         CheckPtrExistence(Window);
  738.         (*Window->UpdateRoutine)(Window->Refcon);
  739.     }
  740.  
  741.  
  742. /* if the program is doing something so that processing an update event would */
  743. /* cause it to crash, then the window is marked and will be redrawn as soon as */
  744. /* possible.   This is used during RelinquishCPU in the EventLoop module since */
  745. /* the windowing system might be in an inconsistent state when that routine is */
  746. /* called.  (If we ignored the event, then the window would not be redrawn at all) */
  747. void                                MarkForDeferredUpdate(WinType* Window)
  748.     {
  749.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  750.         CheckPtrExistence(Window);
  751.         if (ArrayFindElement(PendingDeferredUpdates,Window) < 0)
  752.             {
  753.                 /* don't add it to list unless it isn't there */
  754.                 /* if this fails, then it'll just not redraw the window. */
  755.                 ArrayAppendElement(PendingDeferredUpdates,Window);
  756.             }
  757.     }
  758.  
  759.  
  760. /* redraw all windows whose updates have been deferred */
  761. void                                PerformDeferredUpdates(void)
  762.     {
  763.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  764.         while (ArrayGetLength(PendingDeferredUpdates) != 0)
  765.             {
  766.                 WinType*                    Window;
  767.  
  768.                 /* get the window */
  769.                 Window = (WinType*)ArrayGetElement(PendingDeferredUpdates,0);
  770.                 CheckPtrExistence(Window);
  771.                 /* remove the window from the deferred update list */
  772.                 ArrayDeleteElement(PendingDeferredUpdates,0);
  773.                 /* erase window */
  774.                 SetClipRect(Window,0,0,GetWindowWidth(Window),GetWindowHeight(Window));
  775.                 DrawBoxErase(Window,0,0,GetWindowWidth(Window),GetWindowHeight(Window));
  776.                 /* call the redraw callback */
  777.                 CallWindowUpdate(Window);
  778.             }
  779.     }
  780.  
  781.  
  782. /* get the refcon from the window */
  783. void*                                GetWindowRefcon(WinType* Window)
  784.     {
  785.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  786.         CheckPtrExistence(Window);
  787.         return Window->Refcon;
  788.     }
  789.  
  790.  
  791. /* set the clipping rectangle for the window.  Drawing outside of this rectangle */
  792. /* will not be change any of the window */
  793. void                                SetClipRect(WinType* Window, OrdType Left, OrdType Top,
  794.                                             OrdType Width, OrdType Height)
  795.     {
  796.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  797.         CheckPtrExistence(Window);
  798.         SetPort((WindowPtr)&(Window->ActualWindow));
  799.         Window->CurrentClipRect.left = Left;
  800.         Window->CurrentClipRect.top = Top;
  801.         Window->CurrentClipRect.right = Left + Width;
  802.         Window->CurrentClipRect.bottom = Top + Height;
  803.         ClipRect(&(Window->CurrentClipRect));
  804.     }
  805.  
  806.  
  807. /* constrain the clipping rectangle for the window.  The new clipping rectangle is */
  808. /* the intersection of the specified one and the previous one. */
  809. void                                AddClipRect(WinType* Window, OrdType Left, OrdType Top,
  810.                                             OrdType Width, OrdType Height)
  811.     {
  812.         Rect                            Old;
  813.  
  814.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  815.         CheckPtrExistence(Window);
  816.         SetPort((WindowPtr)&(Window->ActualWindow));
  817.         Old = Window->CurrentClipRect;
  818.         Window->CurrentClipRect.left = Left;
  819.         Window->CurrentClipRect.top = Top;
  820.         Window->CurrentClipRect.right = Left + Width;
  821.         Window->CurrentClipRect.bottom = Top + Height;
  822.         SectRect(&(Window->CurrentClipRect),&Old,&(Window->CurrentClipRect));
  823.         ClipRect(&(Window->CurrentClipRect));
  824.     }
  825.  
  826.  
  827. /* returns True if any part of the specified rectangle in the window is visible. */
  828. /* this is used for making redrawing more efficient. */
  829. MyBoolean                        IsRectVisible(WinType* Window, OrdType Left, OrdType Top,
  830.                                             OrdType Width, OrdType Height)
  831.     {
  832.         Rect                            Location;
  833.  
  834.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  835.         CheckPtrExistence(Window);
  836.         Location.left = Left;
  837.         Location.top = Top;
  838.         Location.right = Left + Width;
  839.         Location.bottom = Top + Height;
  840.         return (MyBoolean)RectInRgn(&Location,Window->ActualWindow.port.visRgn);
  841.     }
  842.  
  843.  
  844. /* Draw a line one pixel thick.  XDisp and YDisp may be negative. */
  845. void                                DrawLine(WinType* Window, Patterns Pattern,
  846.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  847.     {
  848.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  849.         CheckPtrExistence(Window);
  850.         SetPort((WindowPtr)&(Window->ActualWindow));
  851.         PenPat(PatternMapping[Pattern - eWhite]);
  852.         PenMode(srcCopy);
  853.         MoveTo(X,Y);
  854.         LineTo(X + XDisp,Y + YDisp);
  855.     }
  856.  
  857.  
  858. /* Draw a box with a 1 pixel thick frame.  Note that the last pixel touched */
  859. /* is X + XDisp - 1 and Y + YDisp - 1. */
  860. void                                DrawBoxFrame(WinType* Window, Patterns Pattern,
  861.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  862.     {
  863.         Rect                            Temp;
  864.  
  865.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  866.         CheckPtrExistence(Window);
  867.         SetPort((WindowPtr)&(Window->ActualWindow));
  868.         PenPat(PatternMapping[Pattern - eWhite]);
  869.         PenMode(srcCopy);
  870.         Temp.left = X;
  871.         Temp.top = Y;
  872.         Temp.right = X + XDisp;
  873.         Temp.bottom = Y + YDisp;
  874.         FrameRect(&Temp);
  875.     }
  876.  
  877.  
  878. /* paint the box with the specified pattern */
  879. void                                DrawBoxPaint(WinType* Window, Patterns Pattern,
  880.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  881.     {
  882.         Rect                            Temp;
  883.  
  884.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  885.         CheckPtrExistence(Window);
  886.         SetPort((WindowPtr)&(Window->ActualWindow));
  887.         PenPat(PatternMapping[Pattern - eWhite]);
  888.         PenMode(srcCopy);
  889.         Temp.left = X;
  890.         Temp.top = Y;
  891.         Temp.right = X + XDisp;
  892.         Temp.bottom = Y + YDisp;
  893.         PaintRect(&Temp);
  894.     }
  895.  
  896.  
  897. /* paint the box with white */
  898. void                                DrawBoxErase(WinType* Window, OrdType X, OrdType Y,
  899.                                             OrdType XDisp, OrdType YDisp)
  900.     {
  901.         Rect                            Temp;
  902.  
  903.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  904.         CheckPtrExistence(Window);
  905.         SetPort((WindowPtr)&(Window->ActualWindow));
  906.         Temp.left = X;
  907.         Temp.top = Y;
  908.         Temp.right = X + XDisp;
  909.         Temp.bottom = Y + YDisp;
  910.         EraseRect(&Temp);
  911.     }
  912.  
  913.  
  914. #if 0
  915. /* And-mask the contents of the box with the pattern */
  916. void                                DrawBoxScreen(WinType* Window, Patterns Pattern,
  917.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp);
  918.     {
  919.         Rect                            Temp;
  920.  
  921.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  922.         CheckPtrExistence(Window);
  923.         SetPort((WindowPtr)&(Window->ActualWindow));
  924.         PenPat(PatternMapping[Pattern - eWhite]);
  925.         PenMode(srcBic);
  926.         Temp.left = X;
  927.         Temp.top = Y;
  928.         Temp.right = X + XDisp;
  929.         Temp.bottom = Y + YDisp;
  930.         PaintRect(&Temp);
  931.     }
  932. #endif
  933.  
  934.  
  935. /* Draw a box, but round off the corners with circles. */
  936. void                                DrawRoundBoxFrame(WinType* Window, Patterns Pattern,
  937.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp,
  938.                                             OrdType DiameterX, OrdType DiameterY)
  939.     {
  940.         Rect                            Temp;
  941.  
  942.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  943.         CheckPtrExistence(Window);
  944.         SetPort((WindowPtr)&(Window->ActualWindow));
  945.         PenPat(PatternMapping[Pattern - eWhite]);
  946.         PenMode(srcCopy);
  947.         Temp.left = X;
  948.         Temp.top = Y;
  949.         Temp.right = X + XDisp;
  950.         Temp.bottom = Y + YDisp;
  951.         FrameRoundRect(&Temp,DiameterX,DiameterY);
  952.     }
  953.  
  954.  
  955. /* Draw a box, but round off the corners with circles. */
  956. void                                DrawRoundBoxPaint(WinType* Window, Patterns Pattern,
  957.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp,
  958.                                             OrdType DiameterX, OrdType DiameterY)
  959.     {
  960.         Rect                            Temp;
  961.  
  962.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  963.         CheckPtrExistence(Window);
  964.         SetPort((WindowPtr)&(Window->ActualWindow));
  965.         PenPat(PatternMapping[Pattern - eWhite]);
  966.         PenMode(srcCopy);
  967.         Temp.left = X;
  968.         Temp.top = Y;
  969.         Temp.right = X + XDisp;
  970.         Temp.bottom = Y + YDisp;
  971.         PaintRoundRect(&Temp,DiameterX,DiameterY);
  972.     }
  973.  
  974.  
  975. /* Draw a box, but round off the corners with circles. */
  976. void                                DrawRoundBoxErase(WinType* Window, OrdType X, OrdType Y,
  977.                                             OrdType XDisp, OrdType YDisp, OrdType DiameterX, OrdType DiameterY)
  978.     {
  979.         Rect                            Temp;
  980.  
  981.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  982.         CheckPtrExistence(Window);
  983.         SetPort((WindowPtr)&(Window->ActualWindow));
  984.         Temp.left = X;
  985.         Temp.top = Y;
  986.         Temp.right = X + XDisp;
  987.         Temp.bottom = Y + YDisp;
  988.         EraseRoundRect(&Temp,DiameterX,DiameterY);
  989.     }
  990.  
  991.  
  992. void                                DrawCircleFrame(WinType* Window, Patterns Pattern,
  993.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  994.     {
  995.         Rect                            Temp;
  996.  
  997.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  998.         CheckPtrExistence(Window);
  999.         SetPort((WindowPtr)&(Window->ActualWindow));
  1000.         PenPat(PatternMapping[Pattern - eWhite]);
  1001.         PenMode(srcCopy);
  1002.         Temp.left = X;
  1003.         Temp.top = Y;
  1004.         Temp.right = X + XDisp;
  1005.         Temp.bottom = Y + YDisp;
  1006.         FrameOval(&Temp);
  1007.     }
  1008.  
  1009.  
  1010. void                                DrawCirclePaint(WinType* Window, Patterns Pattern,
  1011.                                             OrdType X, OrdType Y, OrdType XDisp, OrdType YDisp)
  1012.     {
  1013.         Rect                            Temp;
  1014.  
  1015.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1016.         CheckPtrExistence(Window);
  1017.         SetPort((WindowPtr)&(Window->ActualWindow));
  1018.         PenPat(PatternMapping[Pattern - eWhite]);
  1019.         PenMode(srcCopy);
  1020.         Temp.left = X;
  1021.         Temp.top = Y;
  1022.         Temp.right = X + XDisp;
  1023.         Temp.bottom = Y + YDisp;
  1024.         PaintOval(&Temp);
  1025.     }
  1026.  
  1027.  
  1028. void                                DrawCircleErase(WinType* Window, OrdType X, OrdType Y,
  1029.                                             OrdType XDisp, OrdType YDisp)
  1030.     {
  1031.         Rect            Temp;
  1032.  
  1033.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1034.         CheckPtrExistence(Window);
  1035.         SetPort((WindowPtr)&(Window->ActualWindow));
  1036.         Temp.left = X;
  1037.         Temp.top = Y;
  1038.         Temp.right = X + XDisp;
  1039.         Temp.bottom = Y + YDisp;
  1040.         EraseOval(&Temp);
  1041.     }
  1042.  
  1043.  
  1044. /* fill a triangle */
  1045. void                                DrawTrianglePaint(WinType* Window, Patterns Pattern, OrdType X1,
  1046.                                             OrdType Y1, OrdType X2, OrdType Y2, OrdType X3, OrdType Y3)
  1047.     {
  1048.         PolyHandle                Poly;
  1049.  
  1050.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1051.         CheckPtrExistence(Window);
  1052.         SetPort((WindowPtr)&(Window->ActualWindow));
  1053.         Poly = OpenPoly();
  1054.         MoveTo(X1,Y1);
  1055.         LineTo(X2,Y2);
  1056.         LineTo(X3,Y3);
  1057.         LineTo(X1,Y1);
  1058.         ClosePoly();
  1059.         PenPat(PatternMapping[Pattern - eWhite]);
  1060.         PenMode(srcCopy);
  1061.         PaintPoly(Poly);
  1062.         KillPoly(Poly);
  1063.     }
  1064.  
  1065.  
  1066. /* Get the ID of a heavier screen font (Macintosh == Chicago) */
  1067. FontType                        GetUglyFont(void)
  1068.     {
  1069.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1070.         return systemFont;
  1071.     }
  1072.  
  1073.  
  1074. /* Get the ID of the default screen font (Macintosh == Geneva) */
  1075. FontType                        GetScreenFont(void)
  1076.     {
  1077.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1078.         return geneva;
  1079.     }
  1080.  
  1081.  
  1082. /* Get the ID of the normal monospaced font, usually courier or monaco */
  1083. FontType                        GetMonospacedFont(void)
  1084.     {
  1085.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1086.         return monaco;
  1087.     }
  1088.  
  1089.  
  1090. /* Get the ID of the named font.  If no such font exists, then it is an error */
  1091. FontType                        GetFontByName(char* Name)
  1092.     {
  1093.         unsigned char            NameTemp[256];
  1094.         long                            Scan;
  1095.         short                            FontID;
  1096.  
  1097.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1098.         Scan = 0;
  1099.         while ((Scan < 255) && (Name[Scan] != 0))
  1100.             {
  1101.                 NameTemp[Scan + 1] = Name[Scan];
  1102.                 Scan += 1;
  1103.             }
  1104.         NameTemp[0] = Scan;
  1105.         GetFNum(NameTemp,&FontID);
  1106. #if DEBUG
  1107.         if (FontID == 0)
  1108.             {
  1109.                 unsigned char            SysFontName[256];
  1110.  
  1111.                 GetFontName(0,SysFontName);
  1112.                 if (!EqualString(NameTemp,SysFontName,False,False))
  1113.                     {
  1114.                         PRERR(AllowResume,"GetFontByName:  font doesn't exist");
  1115.                     }
  1116.             }
  1117. #endif
  1118.         return FontID;
  1119.     }
  1120.  
  1121.  
  1122. /* Get the total number of pixels high a line is using the specified font */
  1123. OrdType                            GetFontHeight(FontType FontID, FontSizeType PointSize)
  1124.     {
  1125.         GrafPort                    Temp;
  1126.         FontInfo                    TheFont;
  1127.  
  1128.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1129.         OpenPort(&Temp);
  1130.         TextFont(FontID);
  1131.         TextFace(0);
  1132.         TextMode(srcCopy);
  1133.         TextSize(PointSize);
  1134.         SpaceExtra(0);
  1135.         GetFontInfo(&TheFont);
  1136.         ClosePort(&Temp);
  1137.         return TheFont.ascent + TheFont.descent + TheFont.leading;
  1138.     }
  1139.  
  1140.  
  1141. /* return a Ptr containing the name of the font, null terminated */
  1142. char*                                GetNameOfFont(FontType FontID)
  1143.     {
  1144.         unsigned char            DaFontName[256];
  1145.         char*                            Temp;
  1146.  
  1147.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1148.         GetFontName(FontID,DaFontName);
  1149.         ERROR(DaFontName[0] == 0,PRERR(AllowResume,"GetNameOfFont:  nonexistent font"));
  1150.         Temp = AllocPtrCanFail(DaFontName[0] + 1,"FontName");
  1151.         if (Temp != NIL)
  1152.             {
  1153.                 CopyData((char*)&(DaFontName[1]),&(Temp[0]),DaFontName[0]);
  1154.                 Temp[DaFontName[0]] = 0;
  1155.             }
  1156.         return Temp;
  1157.     }
  1158.  
  1159.  
  1160. /* get number of fonts */
  1161. long                                GetNumAvailableFonts(void)
  1162.     {
  1163.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1164.         return CountMItems(FunnyFontMenu);
  1165.     }
  1166.  
  1167.  
  1168. /* get the FontType of an indexed font. indices are from 0 to GetNumAvailableFonts - 1 */
  1169. FontType                        GetIndexedFont(long FontIndex)
  1170.     {
  1171.         short                            DaID;
  1172.         unsigned char            DaName[256];
  1173.  
  1174.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1175.         ERROR((FontIndex < 0) || (FontIndex >= GetNumAvailableFonts()),PRERR(ForceAbort,
  1176.             "GetIndexedFont:  index out of range"));
  1177.         /* we cleverly make a menu, pile the fonts in there, and then extract */
  1178.         GetItem(FunnyFontMenu,FontIndex + 1,DaName);
  1179.         GetFNum(DaName,&DaID);
  1180.         return DaID;
  1181.     }
  1182.  
  1183.  
  1184. /* find the total number of pixels long the string of text is */
  1185. OrdType                            LengthOfText(FontType Font, FontSizeType PointSize, char* Text,
  1186.                                             long Length, FontStyleType FontStyle)
  1187.     {
  1188.         GrafPort                    Temp;
  1189.         long                            CurrentLinePixels;
  1190.         Style                            FontThangs;
  1191.  
  1192.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1193.         /* open a temporary port to work from */
  1194.         OpenPort(&Temp);
  1195.         /* set font */
  1196.         TextFont(Font);
  1197.         /* figure out what style to use */
  1198.         FontThangs = 0;
  1199.         if ((FontStyle & eBold) != 0)
  1200.             {
  1201.                 FontThangs |= bold;
  1202.             }
  1203.         if ((FontStyle & eItalic) != 0)
  1204.             {
  1205.                 FontThangs |= italic;
  1206.             }
  1207.         if ((FontStyle & eUnderline) != 0)
  1208.             {
  1209.                 FontThangs |= underline;
  1210.             }
  1211.         TextFace(FontThangs);
  1212.         TextMode(srcCopy);
  1213.         TextSize(PointSize);
  1214.         SpaceExtra(0);
  1215.         /* loop through string & add up lengths */
  1216.         CurrentLinePixels = 0;
  1217.         while (Length > 0)
  1218.             {
  1219.                 if (Length > MAXTEXTSIZING)
  1220.                     {
  1221.                         CurrentLinePixels += TextWidth(Text,0,MAXTEXTSIZING);
  1222.                         Length -= MAXTEXTSIZING;
  1223.                         Text += MAXTEXTSIZING;
  1224.                     }
  1225.                  else
  1226.                     {
  1227.                         CurrentLinePixels += TextWidth(Text,0,Length);
  1228.                         Length = 0;
  1229.                     }
  1230.             }
  1231.         ClosePort(&Temp);
  1232.         return CurrentLinePixels;
  1233.     }
  1234.  
  1235.  
  1236. /* draw a line of text */
  1237. void                                DrawTextLine(WinType* Window, FontType Font, FontSizeType PointSize,
  1238.                                             char* Text, long Length, OrdType X, OrdType Y,
  1239.                                             FontStyleType FontStyle)
  1240.     {
  1241.         FontInfo                    Info;
  1242.         Style                            FontThangs;
  1243.  
  1244.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1245.         ERROR(Text == NIL,PRERR(ForceAbort,"DrawTextLine:  Text is NIL"));
  1246.         CheckPtrExistence(Window);
  1247.         SetPort((WindowPtr)&(Window->ActualWindow));
  1248.         TextFont(Font);
  1249.         FontThangs = 0;
  1250.         if ((FontStyle & eBold) != 0)
  1251.             {
  1252.                 FontThangs |= bold;
  1253.             }
  1254.         if ((FontStyle & eItalic) != 0)
  1255.             {
  1256.                 FontThangs |= italic;
  1257.             }
  1258.         if ((FontStyle & eUnderline) != 0)
  1259.             {
  1260.                 FontThangs |= underline;
  1261.             }
  1262.         TextFace(FontThangs);
  1263.         TextMode(srcCopy);
  1264.         TextSize(PointSize);
  1265.         SpaceExtra(0);
  1266.         GetFontInfo(&Info);
  1267.         MoveTo(X,Y + Info.leading + Info.ascent);
  1268.         while (Length > 0)
  1269.             {
  1270.                 if (Length > MAXTEXTSIZING)
  1271.                     {
  1272.                         DrawText(Text,0,MAXTEXTSIZING);
  1273.                         Length -= MAXTEXTSIZING;
  1274.                         Text += MAXTEXTSIZING;
  1275.                     }
  1276.                  else
  1277.                     {
  1278.                         DrawText(Text,0,Length);
  1279.                         Length = 0;
  1280.                     }
  1281.             }
  1282.         if (Info.leading > 0)
  1283.             {
  1284.                 Rect                EraseMe;
  1285.  
  1286.                 /* since srcCopy doesn't erase the leading, we have to do it. */
  1287.                 EraseMe.left = X;
  1288.                 EraseMe.top = Y;
  1289.                 EraseMe.right = Window->ActualWindow.port.pnLoc.h;
  1290.                 EraseMe.bottom = EraseMe.top + Info.leading;
  1291.                 EraseRect(&EraseMe);
  1292.             }
  1293.     }
  1294.  
  1295.  
  1296. /* draw a line of text, but with white background and black letters */
  1297. void                                InvertedTextLine(WinType* Window, FontType Font,
  1298.                                             FontSizeType PointSize, char* Text, long Length,
  1299.                                             OrdType X, OrdType Y, FontStyleType FontStyle)
  1300.     {
  1301.         FontInfo                    Info;
  1302.         Style                            FontThangs;
  1303.  
  1304.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1305.         CheckPtrExistence(Window);
  1306.         SetPort((WindowPtr)&(Window->ActualWindow));
  1307.         TextFont(Font);
  1308.         FontThangs = 0;
  1309.         if ((FontStyle & eBold) != 0)
  1310.             {
  1311.                 FontThangs |= bold;
  1312.             }
  1313.         if ((FontStyle & eItalic) != 0)
  1314.             {
  1315.                 FontThangs |= italic;
  1316.             }
  1317.         if ((FontStyle & eUnderline) != 0)
  1318.             {
  1319.                 FontThangs |= underline;
  1320.             }
  1321.         TextFace(FontThangs);
  1322.         TextMode(notSrcCopy);
  1323.         TextSize(PointSize);
  1324.         SpaceExtra(0);
  1325.         GetFontInfo(&Info);
  1326.         MoveTo(X,Y + Info.leading + Info.ascent);
  1327.         while (Length > 0)
  1328.             {
  1329.                 if (Length > MAXTEXTSIZING)
  1330.                     {
  1331.                         DrawText(Text,0,MAXTEXTSIZING);
  1332.                         Length -= MAXTEXTSIZING;
  1333.                         Text += MAXTEXTSIZING;
  1334.                     }
  1335.                  else
  1336.                     {
  1337.                         DrawText(Text,0,Length);
  1338.                         Length = 0;
  1339.                     }
  1340.             }
  1341.         if (Info.leading > 0)
  1342.             {
  1343.                 Rect                EraseMe;
  1344.  
  1345.                 /* since srcCopy doesn't erase the leading, we have to do it. */
  1346.                 EraseMe.left = X;
  1347.                 EraseMe.top = Y;
  1348.                 EraseMe.right = Window->ActualWindow.port.pnLoc.h;
  1349.                 EraseMe.bottom = EraseMe.top + Info.leading;
  1350.                 PenPat(qd.black);
  1351.                 PenMode(patCopy);
  1352.                 PaintRect(&EraseMe);
  1353.             }
  1354.     }
  1355.  
  1356.  
  1357. /* move the specified rectangle of of pixels. XDisplacement and YDisplacement */
  1358. /* positive mean to the right and down.  Area opened up is erased with white. */
  1359. /* no area outside of the rectangle is touched. */
  1360. void                                ScrollArea(WinType* Window, OrdType Left, OrdType Top, OrdType Width,
  1361.                                             OrdType Height, OrdType XDisplacement, OrdType YDisplacement)
  1362.     {
  1363.         Rect                            Where;
  1364.         RgnHandle                    UpdateRegion;
  1365.         RgnHandle                    ScreenRegion;
  1366.  
  1367.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1368.         CheckPtrExistence(Window);
  1369.         SetPort((WindowPtr)&(Window->ActualWindow));
  1370.         Where.left = Left;
  1371.         Where.top = Top;
  1372.         Where.right = Left + Width;
  1373.         Where.bottom = Top + Height;
  1374.         UpdateRegion = NewRgn();
  1375.         if (UpdateRegion != NIL)
  1376.             {
  1377.                 ScrollRect(&Where,XDisplacement,YDisplacement,UpdateRegion);
  1378.                 /* we discard the update region because the scroller is expected to redraw */
  1379.                 /* it himself without getting and update event */
  1380.                 DisposeRgn(UpdateRegion);
  1381.             }
  1382.     }
  1383.  
  1384.  
  1385. /* convert a raw packed-byte list of data (upper bit of each byte is leftmost */
  1386. /* on the screen) to an internal bitmap */
  1387. Bitmap*                            MakeBitmap(char* RawData, OrdType Width, OrdType Height,
  1388.                                             long BytesPerRow)
  1389.     {
  1390.         short                            TrueBytesPerRow;
  1391.         short                            RowScan;
  1392.         short                            ColumnScan;
  1393.         long                            MapIndex;
  1394.         Bitmap*                        Data;
  1395.  
  1396.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1397.         ERROR(RawData == NIL,PRERR(ForceAbort,"MakeBitmap:  data is NIL"));
  1398.         /* calculate local bytes per row so that it's a long-word multiple */
  1399.         TrueBytesPerRow = ((Width + (8 * sizeof(long)) - 1) / (8 * sizeof(long))) * 4;
  1400.         Data = (Bitmap*)AllocPtrCanFail(TrueBytesPerRow * Height + sizeof(Bitmap),"Bitmap");
  1401.         if (Data == NIL)
  1402.             {
  1403.                 return NIL;
  1404.             }
  1405.         MapIndex = 0;
  1406.         for (RowScan = 0; RowScan < Height; RowScan += 1)
  1407.             {
  1408.                 /* copy over one row worth of data */
  1409.                 for (ColumnScan = 0; ColumnScan < BytesPerRow; ColumnScan += 1)
  1410.                     {
  1411.                         Data->Data[MapIndex + ColumnScan] = RawData[ColumnScan];
  1412.                     }
  1413.                 /* pad the extra space with zeros */
  1414.                 for (ColumnScan = 0; ColumnScan < TrueBytesPerRow - BytesPerRow;
  1415.                     ColumnScan += 1)
  1416.                     {
  1417.                         Data->Data[MapIndex + ColumnScan + BytesPerRow] = 0;
  1418.                     }
  1419.                 MapIndex += TrueBytesPerRow;
  1420.                 RawData += BytesPerRow;
  1421.             }
  1422.         /* assign internal values */
  1423.         Data->Width = Width;
  1424.         Data->Height = Height;
  1425.         Data->BytesPerRow = TrueBytesPerRow;
  1426.         /* initialize the system's bitmap */
  1427.         Data->SystemBitmap.baseAddr = Data->Data;
  1428.         Data->SystemBitmap.rowBytes = TrueBytesPerRow;
  1429.         Data->SystemBitmap.bounds.left = 0;
  1430.         Data->SystemBitmap.bounds.top = 0;
  1431.         Data->SystemBitmap.bounds.right = Data->Width;
  1432.         Data->SystemBitmap.bounds.bottom = Data->Height;
  1433.         return Data;
  1434.     }
  1435.  
  1436.  
  1437. /* dispose of the bitmap made by MakeBitmap */
  1438. void                                DisposeBitmap(Bitmap* TheBitmap)
  1439.     {
  1440.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1441.         ReleasePtr((char*)TheBitmap);
  1442.     }
  1443.  
  1444.  
  1445. /* copy the bitmap to the area specified. */
  1446. void                                DrawBitmap(WinType* Window, OrdType X, OrdType Y, Bitmap* TheBitmap)
  1447.     {
  1448.         Rect                            DestRect;
  1449.  
  1450.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1451.         CheckPtrExistence(Window);
  1452.         CheckPtrExistence(TheBitmap);
  1453.         SetPort((WindowPtr)&(Window->ActualWindow));
  1454.         DestRect.left = X;
  1455.         DestRect.top = Y;
  1456.         DestRect.right = X + TheBitmap->Width;
  1457.         DestRect.bottom = Y + TheBitmap->Height;
  1458.         CopyBits(&(TheBitmap->SystemBitmap),&(Window->ActualWindow.port.portBits),
  1459.             &(TheBitmap->SystemBitmap.bounds),&DestRect,srcCopy,NIL);
  1460.     }
  1461.  
  1462.  
  1463. /* logical-or the bitmap onto the window */
  1464. void                                OrBitmap(WinType* Window, OrdType X, OrdType Y, Bitmap* TheBitmap)
  1465.     {
  1466.         Rect                            DestRect;
  1467.  
  1468.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1469.         CheckPtrExistence(Window);
  1470.         CheckPtrExistence(TheBitmap);
  1471.         SetPort((WindowPtr)&(Window->ActualWindow));
  1472.         DestRect.left = X;
  1473.         DestRect.top = Y;
  1474.         DestRect.right = X + TheBitmap->Width;
  1475.         DestRect.bottom = Y + TheBitmap->Height;
  1476.         CopyBits(&(TheBitmap->SystemBitmap),&(Window->ActualWindow.port.portBits),
  1477.             &(TheBitmap->SystemBitmap.bounds),&DestRect,srcOr,NIL);
  1478.     }
  1479.  
  1480.  
  1481. /* Bit-clear the bitmap onto the window:  Where the bitmap is set, the */
  1482. /* window will be erased; otherwise the window will be untouched */
  1483. void                                BicBitmap(WinType* Window, OrdType X, OrdType Y, Bitmap* TheBitmap)
  1484.     {
  1485.         Rect                            DestRect;
  1486.  
  1487.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1488.         CheckPtrExistence(Window);
  1489.         CheckPtrExistence(TheBitmap);
  1490.         SetPort((WindowPtr)&(Window->ActualWindow));
  1491.         DestRect.left = X;
  1492.         DestRect.top = Y;
  1493.         DestRect.right = X + TheBitmap->Width;
  1494.         DestRect.bottom = Y + TheBitmap->Height;
  1495.         CopyBits(&(TheBitmap->SystemBitmap),&(Window->ActualWindow.port.portBits),
  1496.             &(TheBitmap->SystemBitmap.bounds),&DestRect,srcBic,NIL);
  1497.     }
  1498.  
  1499.  
  1500. /* duplicate the bitmap */
  1501. Bitmap*                            DuplicateBitmap(Bitmap* Original)
  1502.     {
  1503.         Bitmap*                        Copy;
  1504.         long                            TotalSize;
  1505.  
  1506.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1507.         CheckPtrExistence(Original);
  1508.         /* this is easy since there are no sub-objects */
  1509.         TotalSize = PtrSize((char*)Original);
  1510.         Copy = (Bitmap*)AllocPtrCanFail(TotalSize,"DuplicateBitmap");
  1511.         if (Copy != NIL)
  1512.             {
  1513.                 CopyData((char*)Original,(char*)Copy,TotalSize);
  1514.                 Copy->SystemBitmap.baseAddr = Copy->Data;
  1515.             }
  1516.         return Copy;
  1517.     }
  1518.  
  1519.  
  1520. /* logical-or the first bitmap onto the second.  sizes must be the same */
  1521. void                                BitmapOrIntoBitmap(Bitmap* NotChanged, Bitmap* IsChanged)
  1522.     {
  1523.         long                            Scan;
  1524.         long                            Limit;
  1525.  
  1526.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1527.         CheckPtrExistence(NotChanged);
  1528.         CheckPtrExistence(IsChanged);
  1529.         ERROR((NotChanged->BytesPerRow != IsChanged->BytesPerRow)
  1530.             || (NotChanged->Width != IsChanged->Width)
  1531.             || (NotChanged->Height != IsChanged->Height),PRERR(ForceAbort,
  1532.             "BitmapOrIntoBitmap:  bitmaps are not the same size"));
  1533.         /* we can perform operations on long words since we ensure that our */
  1534.         /* internal bitmap representation is long-word aligned */
  1535.         Limit = (IsChanged->BytesPerRow * IsChanged->Height) / sizeof(unsigned long);
  1536.         for (Scan = 0; Scan < Limit; Scan += 1)
  1537.             {
  1538.                 PRNGCHK(IsChanged,&(((unsigned long*)(IsChanged->Data))[Scan]),
  1539.                     sizeof(unsigned long));
  1540.                 PRNGCHK(NotChanged,&(((unsigned long*)(NotChanged->Data))[Scan]),
  1541.                     sizeof(unsigned long));
  1542.                 ((unsigned long*)(IsChanged->Data))[Scan]
  1543.                     |= ((unsigned long*)(NotChanged->Data))[Scan];
  1544.             }
  1545.     }
  1546.  
  1547.  
  1548. /* logical-and the first bitmap onto the second.  sizes must be the same */
  1549. void                                BitmapAndIntoBitmap(Bitmap* NotChanged, Bitmap* IsChanged)
  1550.     {
  1551.         long                            Scan;
  1552.         long                            Limit;
  1553.  
  1554.         ERROR(!Initialized,PRERR(ForceAbort,"Screen subsystem hasn't been initialized"));
  1555.         CheckPtrExistence(NotChanged);
  1556.         CheckPtrExistence(IsChanged);
  1557.         ERROR((NotChanged->BytesPerRow != IsChanged->BytesPerRow)
  1558.             || (NotChanged->Width != IsChanged->Width)
  1559.             || (NotChanged->Height != IsChanged->Height),PRERR(ForceAbort,
  1560.             "BitmapAndIntoBitmap:  bitmaps are not the same size"));
  1561.         /* we can perform operations on long words since we ensure that our */
  1562.         /* internal bitmap representation is long-word aligned */
  1563.         Limit = (IsChanged->BytesPerRow * IsChanged->Height) / sizeof(unsigned long);
  1564.         for (Scan = 0; Scan < Limit; Scan += 1)
  1565.             {
  1566.                 PRNGCHK(IsChanged,&(((unsigned long*)(IsChanged->Data))[Scan]),
  1567.                     sizeof(unsigned long));
  1568.                 PRNGCHK(NotChanged,&(((unsigned long*)(NotChanged->Data))[Scan]),
  1569.                     sizeof(unsigned long));
  1570.                 ((unsigned long*)(IsChanged->Data))[Scan]
  1571.                     &= ((unsigned long*)(NotChanged->Data))[Scan];
  1572.             }
  1573.     }
  1574.